
import { createServer } from "http";
import { Server } from 'socket.io';
import { v4 as uuidv4 } from "uuid";
// todo: 动态生成port
// const portfinder from 'portfinder');

/**
 *
 * 通信方式 electron-render <——> electron-main  <——> bridge-server <——> bridge-client <——> chrome-extension
 */
class BridgeServer {

  io: Server | null = null;
  socketMap = new Map();
  pendingRequests = new Map();

  constructor() {
    this.setupConnection()
  }

  setupConnection() {
    try {
      const httpServer = createServer();
      this.io = new Server(httpServer, {
        maxHttpBufferSize: 100 * 1024 * 1024, // 100MB
        pingTimeout: 60000,
        pingInterval: 10000
      });

      this.io.on("connection", (socket) => {

        console.log(`socket ${socket.id} connected`);

        this.socketMap.set(socket.id, socket);

        // 断开连接
        socket.on('disconnect', (reason) => {
          console.log(`socket ${socket.id} disconnected due to ${reason}`);
          this.cleanup(socket.id);
          this.socketMap.delete(socket.id);
        });

        socket.on('error', () => {
          console.log('socket error')
        });

        // client发来消息
        socket.on('bridge:message', async (message) => {
          console.log('bridge:message', message)

          if (!message || typeof message !== 'object') {
            this.sendMessage(socket.id, {
              error: 'Invalid message format'
            });
            return;
          }

          if (message.responseId) {
            const requestId = message.responseId;
            const pending = this.pendingRequests.get(requestId);
            if (pending) {
              clearTimeout(pending.timeoutId);
              if (message.error) {
                pending.resolve({
                  error: message.error
                });
              } else {
                pending.resolve(message.payload);
              }
              this.pendingRequests.delete(requestId);
            }
            return;
          }

          if (message.payload?.type === 'ping_from_client') {
            // 收到ping,返回pong
            this.sendMessage(socket.id, {
              responseId: message.requestId,
              payload: {
                type: 'pong_to_client'
              }
            })
            return
          }

          // 有requestId需要响应
          if (message.requestId) {
            // 模拟成功响应
            this.sendMessage(socket.id, {
              responseId: message.requestId,
              payload: {
                message: 'server执行成功'
              }
            })
          }
        })
      })
      // this.io.use((socket, next) => {
      //     if (this.socketMap) {
      //         next(new Error('server already connected by another client'));
      //     }
      //     next();
      // });
      httpServer.listen(9988);
    } catch (error) {

    }
  }

  // 给bridgeClient发送消息并等待结果
  invokeMessage(payload, type = 'native', timeoutMs = 30000) {
    return new Promise((resolve, reject) => {
      if (!this.socketMap.size) {
        resolve({
          error: '等待client建立连接'
        })
      }
      for (let [socketId, socket] of this.socketMap) {
        const requestId = `${socketId}${uuidv4()}`; // Generate unique request ID

        const timeoutId = setTimeout(() => {
          this.pendingRequests.delete(requestId); // Remove from Map after timeout
          resolve({
            error: `Request timed out after ${timeoutMs}ms`
          });
        }, timeoutMs);

        this.pendingRequests.set(requestId, { resolve, reject, timeoutId });

        this.sendMessage(socketId, {
          requestId,
          type,
          payload
        })
      }
    });
  }

  // 给bridgeClient发送消息
  sendMessage(socketId, message) {
    if (!message || typeof message !== 'object') {
      throw Error('Invalid message format')
    }
    if (socketId) {
      const socket = this.socketMap.get(socketId)
      socket?.emit(
        'bridge:message',
        message,
        () => {
          socket?.disconnect()
        })
    } else {
      this.socketMap.forEach(socket => {
        socket?.emit(
          'bridge:message',
          message,
          () => {
            socket?.disconnect()
          })
      })
    }
  }

  cleanup(id) {
    if (id) {
      // Reject all pending requests by requestId
      for (let [requestId, pending] of this.pendingRequests) {
        if (requestId.startsWith(id)) {
          clearTimeout(pending.timeoutId);
          pending.reject(new Error('Native host is shutting down or Chrome disconnected.'));
          this.pendingRequests.delete(id)
        }
      }
    } else {
      // Reject all pending requests
      this.pendingRequests.forEach((pending) => {
        clearTimeout(pending.timeoutId);
        pending.reject(new Error('Native host is shutting down or Chrome disconnected.'));
      });
      this.pendingRequests.clear();
    }
  }

}

const bridgeServer = new BridgeServer()

// setInterval(() => {
//   bridgeServer.invokeMessage({
//     type: 'ping_from_server'
//   }).then(res => {
//     console.log(res)
//   })
// }, 5000)

export {
  bridgeServer
}
